package cc.autoapi.pucong.auto.flow.provider.api.manager;


import cc.autoapi.pucong.auto.flow.core.flow.execNode.entity.api.design.ApiNodeParamsVo;
import cc.autoapi.pucong.auto.flow.core.flow.execNode.entity.api.design.ApiNodeRelationVo;
import cc.autoapi.pucong.auto.flow.core.flow.execNode.entity.api.design.ApiNodeVo;
import cc.autoapi.pucong.auto.flow.core.flow.execNode.entity.node.NodeParamIn;
import cc.autoapi.pucong.auto.flow.core.flow.execNode.entity.node.NodeParamOut;
import cc.autoapi.pucong.auto.flow.core.flow.execNode.selfenum.NodeTypeEnum;
import cc.autoapi.pucong.auto.flow.core.flow.execNode.task.AbstractTask;
import cc.autoapi.pucong.auto.flow.core.flow.execNode.task.TaskFactory;
import cc.autoapi.pucong.auto.flow.core.flow.execNode.utils.FlowDesignUtils;
import cc.autoapi.pucong.auto.flow.core.root.utils.UUID;
import cc.autoapi.pucong.auto.flow.persistence.po.node.NodeInfoPo;
import cc.autoapi.pucong.auto.flow.persistence.po.node.NodeParamsPo;
import cc.autoapi.pucong.auto.flow.persistence.po.sys.GroupInfoPo;
import cc.autoapi.pucong.auto.flow.persistence.repository.api.ApiNodeService;
import cc.autoapi.pucong.auto.flow.persistence.repository.node.NodeInfoService;
import cc.autoapi.pucong.auto.flow.persistence.repository.node.NodeParamsService;
import cc.autoapi.pucong.auto.flow.provider.api.entity.dto.ApiNodePreDto;
import cc.autoapi.pucong.auto.flow.provider.api.entity.dto.ApiNodeScriptAiDto;
import cc.autoapi.pucong.auto.flow.provider.api.entity.dto.ApiNodeTextAiDto;
import cc.autoapi.pucong.auto.flow.provider.api.entity.qo.ApiNodeQo;
import cc.autoapi.pucong.auto.flow.provider.api.entity.vo.ApiNodeParamsInVo;
import cc.autoapi.pucong.auto.flow.provider.api.entity.vo.ApiNodeParamsOutVo;
import cc.autoapi.pucong.auto.flow.provider.api.entity.vo.ApiNodePreTreeVo;
import cc.autoapi.pucong.auto.flow.provider.api.entity.vo.ApiNodeTreeVo;
import cc.autoapi.pucong.auto.flow.provider.group.service.GroupInfoService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @author pucong
 * @description api 关联节点信息 managerService 实现类
 * @create 2024-09-24
 */
@Service
@Slf4j
public class ApiNodeManager {

    @Resource
    private ApiNodeService apiNodeService;

    @Resource
    private GroupInfoService groupInfoService;

    @Resource
    private NodeInfoService nodeInfoService;

    @Resource
    private NodeParamsService nodeParamsService;

    public List<ApiNodeTreeVo> getList(ApiNodeQo dto) {
        String nodeName = dto.getNodeName();

        List<ApiNodeTreeVo> vos = new ArrayList<>();
        NodeTypeEnum[] values = NodeTypeEnum.values();
        for (NodeTypeEnum value : values) {
            AbstractTask task = TaskFactory.getTask(value);
            if (StringUtils.isNotBlank(nodeName) && !task.getTaskName().contains(nodeName)) {
                continue;
            }
            ApiNodeTreeVo base1 = new ApiNodeTreeVo();
            base1.setUuid(UUID.uuid());
            base1.setNodeName(task.getTaskName());
            base1.setNodeCode(value.getKey());
            base1.setDesc(task.getTaskDesc());
            base1.setSvgIcon(task.getTaskSvgIcon());
            base1.setParamInAuto(task.getTaskParamInAuto());
            base1.setParentId(task.getTaskClassId());
            List<NodeParamIn> propertyParamsIns = task.getPropertyParamsIns();
            List<ApiNodeParamsInVo> paramsInList = new ArrayList<>();
            for (NodeParamIn nodeParamIn : propertyParamsIns) {
                ApiNodeParamsInVo apiNodeParamsInVo = new ApiNodeParamsInVo();
                apiNodeParamsInVo.setParamCode(nodeParamIn.getParamCode());
                apiNodeParamsInVo.setDateType(nodeParamIn.getDateType().getType());
                apiNodeParamsInVo.setDefaultValue(null);
                apiNodeParamsInVo.setNeedValue(nodeParamIn.getNeedValue());
                apiNodeParamsInVo.setDesc(nodeParamIn.getDesc());
                paramsInList.add(apiNodeParamsInVo);
            }
            base1.setParamsInList(paramsInList);
            List<ApiNodeParamsOutVo> paramsOutList = new ArrayList<>();
            List<NodeParamOut> propertyParamsOuts = task.getPropertyParamsOuts();
            for (NodeParamOut nodeParamOut : propertyParamsOuts) {
                ApiNodeParamsOutVo apiNodeParamsOutVo = new ApiNodeParamsOutVo();
                apiNodeParamsOutVo.setParamCode(nodeParamOut.getParamCode());
                apiNodeParamsOutVo.setDateType(nodeParamOut.getDateType().getType());
                apiNodeParamsOutVo.setDesc(nodeParamOut.getDesc());
                paramsOutList.add(apiNodeParamsOutVo);
            }
            base1.setParamsOutList(paramsOutList);
            base1.setTreeType(1);
            vos.add(base1);
        }

        Set<String> taskMapKey = TaskFactory.getTaskMapKey();
        for (String s : taskMapKey) {
            AbstractTask task = TaskFactory.getTask(s);
            if (StringUtils.isNotBlank(nodeName) && !task.getTaskName().contains(nodeName)) {
                continue;
            }
            ApiNodeTreeVo extend1 = new ApiNodeTreeVo();
            extend1.setUuid(UUID.uuid());
            extend1.setNodeName(task.getTaskName());
            extend1.setNodeCode(s);
            extend1.setDesc(task.getTaskDesc());
            extend1.setSvgIcon(task.getTaskSvgIcon());
            extend1.setParamInAuto(task.getTaskParamInAuto());
            extend1.setParentId(task.getTaskClassId());
            List<NodeParamIn> propertyParamsIns = task.getPropertyParamsIns();
            List<ApiNodeParamsInVo> paramsInList = new ArrayList<>();
            for (NodeParamIn nodeParamIn : propertyParamsIns) {
                ApiNodeParamsInVo apiNodeParamsInVo = new ApiNodeParamsInVo();
                apiNodeParamsInVo.setParamCode(nodeParamIn.getParamCode());
                apiNodeParamsInVo.setDateType(nodeParamIn.getDateType().getType());
                apiNodeParamsInVo.setDefaultValue(null);
                apiNodeParamsInVo.setNeedValue(nodeParamIn.getNeedValue());
                apiNodeParamsInVo.setDesc(nodeParamIn.getDesc());
                paramsInList.add(apiNodeParamsInVo);
            }
            extend1.setParamsInList(paramsInList);
            List<ApiNodeParamsOutVo> paramsOutList = new ArrayList<>();
            List<NodeParamOut> propertyParamsOuts = task.getPropertyParamsOuts();
            for (NodeParamOut nodeParamOut : propertyParamsOuts) {
                ApiNodeParamsOutVo apiNodeParamsOutVo = new ApiNodeParamsOutVo();
                apiNodeParamsOutVo.setParamCode(nodeParamOut.getParamCode());
                apiNodeParamsOutVo.setDateType(nodeParamOut.getDateType().getType());
                apiNodeParamsOutVo.setDesc(nodeParamOut.getDesc());
                paramsOutList.add(apiNodeParamsOutVo);
            }
            extend1.setParamsOutList(paramsOutList);
            extend1.setTreeType(1);
            vos.add(extend1);
        }
        // 查询数据库脚本
        List<NodeInfoPo> nodeInfoPos = nodeInfoService.list(1);
        if (nodeInfoPos.size() > 0) {
            List<String> nodeInfoIds = nodeInfoPos.stream().map(NodeInfoPo::getUuid).collect(Collectors.toList());
            List<NodeParamsPo> list = nodeParamsService.list(nodeInfoIds);
            Map<String, List<NodeParamsPo>> execParamOutMap = list.stream().collect(Collectors.groupingBy(NodeParamsPo::getNodeId));
            for (NodeInfoPo nodeInfoPo : nodeInfoPos) {
                ApiNodeTreeVo extend1 = new ApiNodeTreeVo();
                extend1.setUuid(nodeInfoPo.getUuid());
                extend1.setNodeName(nodeInfoPo.getNodeName());
                extend1.setNodeCode(nodeInfoPo.getNodeCode());
                extend1.setDesc(nodeInfoPo.getNodeDesc());
                extend1.setSvgIcon(nodeInfoPo.getNodeIcoId());
                extend1.setParamInAuto(false);
                extend1.setParentId(nodeInfoPo.getGroupId());

                List<NodeParamsPo> nodeParamsPos = execParamOutMap.get(nodeInfoPo.getUuid());
                List<ApiNodeParamsInVo> paramsInList = new ArrayList<>();
                List<ApiNodeParamsOutVo> paramsOutList = new ArrayList<>();
                if (nodeParamsPos != null) {
                    for (NodeParamsPo nodeParamsPo : nodeParamsPos) {
                        if (nodeParamsPo.getParamType() == 0) {
                            ApiNodeParamsInVo apiNodeParamsInVo = new ApiNodeParamsInVo();
                            apiNodeParamsInVo.setParamCode(nodeParamsPo.getParamCode());
                            apiNodeParamsInVo.setDateType(nodeParamsPo.getDateType());
                            apiNodeParamsInVo.setDefaultValue(null);
                            apiNodeParamsInVo.setNeedValue(nodeParamsPo.getNeedValue() == 1);
                            apiNodeParamsInVo.setDesc(nodeParamsPo.getParamDesc());
                            paramsInList.add(apiNodeParamsInVo);
                        } else {
                            ApiNodeParamsOutVo apiNodeParamsOutVo = new ApiNodeParamsOutVo();
                            apiNodeParamsOutVo.setParamCode(nodeParamsPo.getParamCode());
                            apiNodeParamsOutVo.setDateType(nodeParamsPo.getDateType());
                            apiNodeParamsOutVo.setDesc(nodeParamsPo.getParamDesc());
                            paramsOutList.add(apiNodeParamsOutVo);
                        }
                    }
                }
                extend1.setParamsInList(paramsInList);
                extend1.setParamsOutList(paramsOutList);
                vos.add(extend1);
            }
        }
        if (vos.size() > 0) {
            List<String> groupIds = vos.stream().map(ApiNodeTreeVo::getParentId).collect(Collectors.toList());
            List<GroupInfoPo> groupInfoPos = groupInfoService.listByIds(groupIds);
            // 排序
            groupInfoPos.sort(Comparator.comparing(GroupInfoPo::getSortIndex));
            for (GroupInfoPo groupInfoPo : groupInfoPos) {
                ApiNodeTreeVo base = new ApiNodeTreeVo();
                base.setUuid(groupInfoPo.getUuid());
                base.setNodeName(groupInfoPo.getName());
                base.setTreeType(0);
                vos.add(base);
            }
        }
        return vos;
    }

    public String getScriptByAi(ApiNodeScriptAiDto dto) {
        return apiNodeService.getScriptByAi(dto.getNodeName(), dto.getDesc(), dto.getNodeType(),
                dto.getIns(), dto.getOuts());
    }

    public List<ApiNodePreTreeVo> getPreData(ApiNodePreDto dto) {
        String apiNodeId = dto.getNodeId();
        List<ApiNodeRelationVo> addRelateList = new ArrayList<>();
        List<ApiNodeVo> addNodeList = new ArrayList<>();
        List<ApiNodeParamsVo> apiNodeParamsVoList = new ArrayList<>();
        // 解析json
        FlowDesignUtils.dealJson2List(dto.getApiJson(),
                addNodeList, addRelateList,
                apiNodeParamsVoList);


        List<ApiNodePreTreeVo> vos = new ArrayList<>();
        // 如果当前节点是循环，则设置默认循环参数
        ApiNodeVo byId = addNodeList.stream().filter(apiNodePo -> apiNodeId.equals(apiNodePo.getUuid())).findFirst().orElse(null);
        if (byId != null && NodeTypeEnum.FOR.getKey().equals(byId.getNodeType())) {
            ApiNodePreTreeVo tree = new ApiNodePreTreeVo();
            tree.setUuid(byId.getUuid());
            tree.setNodeName(byId.getNodeName());
            tree.setNodeCode(byId.getNodeType());
            tree.setDesc(byId.getNodeDesc());
            tree.setParentId("");
            tree.setTreeType(1);
            vos.add(tree);

            ApiNodePreTreeVo itemKey = new ApiNodePreTreeVo();
            itemKey.setUuid("itemKey");
            itemKey.setNodeName("itemKey");
            itemKey.setNodeCode("itemKey");
            itemKey.setDesc("循环的key值");
            itemKey.setParentId(byId.getUuid());
            itemKey.setTreeType(0);
            vos.add(itemKey);

            ApiNodePreTreeVo itemValue = new ApiNodePreTreeVo();
            itemValue.setUuid("itemValue");
            itemValue.setNodeName("itemValue");
            itemValue.setNodeCode("itemValue");
            itemValue.setDesc("循环val值");
            itemValue.setParentId(byId.getUuid());
            itemValue.setTreeType(0);
            vos.add(itemValue);
        }
        // 查询前置节点
        List<String> projectApiNodeIds = getPre(addRelateList, apiNodeId);
        if (projectApiNodeIds.size() > 0) {
            // 设置前置节点
            List<ApiNodeVo> projectApiNodes = addNodeList.stream().filter(apiNodePo -> projectApiNodeIds.contains(apiNodePo.getUuid())).collect(Collectors.toList());
            if (projectApiNodes.size() > 0) {
                for (ApiNodeVo apiNode : projectApiNodes) {
                    ApiNodePreTreeVo tree = new ApiNodePreTreeVo();
                    tree.setUuid(apiNode.getUuid());
                    tree.setNodeName(apiNode.getNodeName());
                    tree.setNodeCode(apiNode.getNodeType());
                    tree.setDesc(apiNode.getNodeDesc());
                    tree.setParentId("");
                    tree.setTreeType(1);
                    vos.add(tree);
                }
                // 查询节点参数
                Map<String, ApiNodeVo> apiNodePoMap = projectApiNodes.stream().collect(Collectors.toMap(ApiNodeVo::getUuid, s -> s));
                List<ApiNodeParamsVo> apiNodeParamsPoList = apiNodeParamsVoList.stream().filter(apiNodePo -> projectApiNodeIds.contains(apiNodePo.getApiNodeId())).collect(Collectors.toList());

                for (ApiNodeParamsVo apiNodeParamsPo : apiNodeParamsPoList) {
                    ApiNodeVo apiNodePo = apiNodePoMap.get(apiNodeParamsPo.getApiNodeId());
                    if (apiNodePo.getNodeType().equals(NodeTypeEnum.API_CONFIG.getKey()) && apiNodeParamsPo.getParamType() == 1) {
                        continue;
                    } else if (apiNodePo.getNodeType().equals(NodeTypeEnum.CRON_CONFIG.getKey())) {
                        continue;
                    } else if (!apiNodePo.getNodeType().equals(NodeTypeEnum.API_CONFIG.getKey())
                            && !apiNodePo.getNodeType().equals(NodeTypeEnum.CRON_CONFIG.getKey())
                            && apiNodeParamsPo.getParamType() != 1) {
                        continue;
                    }
                    ApiNodePreTreeVo tree = new ApiNodePreTreeVo();
                    if (apiNodeParamsPo.getParamType() == 0) {
                        tree.setUuid(apiNodeParamsPo.getApiNodeId() + "_in_" + apiNodeParamsPo.getParamCode());
                    } else {
                        tree.setUuid(apiNodeParamsPo.getApiNodeId() + "_out_" + apiNodeParamsPo.getParamCode());
                    }
                    tree.setNodeName(apiNodeParamsPo.getParamCode());
                    tree.setNodeCode(apiNodeParamsPo.getParamCode());
                    tree.setDesc(apiNodeParamsPo.getParamDesc());
                    tree.setParentId(apiNodeParamsPo.getApiNodeId());
                    tree.setTreeType(0);
                    vos.add(tree);
                }
            }
        }
        return vos;
    }

    private List<String> getPre(List<ApiNodeRelationVo> relateLists, String id) {
        List<String> preNodeRelations = new ArrayList<>();
        for (ApiNodeRelationVo apiNodeRelation : relateLists) {
            if (apiNodeRelation.getNodeToId().equals(id)) {
                preNodeRelations.add(apiNodeRelation.getNodeFromId());
                preNodeRelations.addAll(getPre(relateLists, apiNodeRelation.getNodeFromId()));
            }
        }
        return preNodeRelations;
    }

    public String getTextByAi(ApiNodeTextAiDto dto) {
        return apiNodeService.getTextByAi(dto.getDesc(), dto.getContent());
    }
}
